package cn.microservices.cloud.gateway.util.token;

import cn.microservices.cloud.gateway.util.Constant;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

public class TokenManager {

    private static Long tokenValidSeconds = 60 * 60 * 24 * 7L;

    private static String signSalt = "metagross";

    private static String json = "_json_";

    private RedisTemplate redis;

    public Token getToken(String key) {
        if (StringUtils.isBlank(key)) return null;
        Object o = redis.opsForValue().get(Constant.REDIS_KEY_TOKEN_PREFIX + key);
        if (o != null) return (Token) o;
        return null;
    }

    public String getJsonToken(String key) {
        if (StringUtils.isBlank(key)) return null;
        Object o = redis.opsForValue().get(Constant.REDIS_KEY_TOKEN_PREFIX + json + key);
        if (o != null) return  o.toString();
        return null;
    }

    /**
     * 放入redis时，有效期为tokenValidSeconds的两倍
     * 也就是当token中的expiresIn过期后，有相同的时长可用于refreshToken
     * <p>
     * build.2020-07-21版本修正
     */
    public void putToken(Token token) {

        // 保存token
        redis.opsForValue().set(Constant.REDIS_KEY_TOKEN_PREFIX + token.getKey(), token, tokenValidSeconds * 2, TimeUnit.SECONDS);
        // 将当前token放入以用户id和身份为key的list中，当用户重新登录时，将这个list中对应的token全部删除，防止多次登录后token无法管理的问题
        String listKey = Constant.REDIS_KEY_TOKEN_LIST_PREFIX + token.getSubjectClass() + "_" + token.getSubjectId();
        redis.opsForList().rightPush(listKey, token.getKey());
        // 将这个list的过期时间设置为和最后一个token的过期时间相同
        redis.expire(listKey, tokenValidSeconds * 2, TimeUnit.SECONDS);

        // 保存token
        redis.opsForValue().set(Constant.REDIS_KEY_TOKEN_PREFIX + json + token.getKey(), JSONObject.toJSONString(token), tokenValidSeconds * 2, TimeUnit.SECONDS);
        // 将当前token放入以用户id和身份为key的list中，当用户重新登录时，将这个list中对应的token全部删除，防止多次登录后token无法管理的问题
        String listJsonKey = Constant.REDIS_KEY_TOKEN_LIST_PREFIX + json + token.getSubjectClass() + "_" + token.getSubjectId();
        redis.opsForList().rightPush(listJsonKey, token.getKey());
        // 将这个list的过期时间设置为和最后一个token的过期时间相同
        redis.expire(listJsonKey, tokenValidSeconds * 2, TimeUnit.SECONDS);
    }

    public void removeToken(String subjectId, String subjectClass) {
        String listKey = Constant.REDIS_KEY_TOKEN_LIST_PREFIX + subjectClass + "_" + subjectId;
        while (redis.opsForList().size(listKey) > 0) {
            Object o = redis.opsForList().leftPop(listKey);
            if (o != null)
                redis.delete(Constant.REDIS_KEY_TOKEN_PREFIX + o);
        }


        String listJsonKey = Constant.REDIS_KEY_TOKEN_LIST_PREFIX + json + subjectClass + "_" + subjectId;
        while (redis.opsForList().size(listJsonKey) > 0) {
            Object o = redis.opsForList().leftPop(listJsonKey);
            if (o != null)
                redis.delete(Constant.REDIS_KEY_TOKEN_PREFIX + json + o);
        }
    }

    public static Long getTokenValidSeconds() {
        return tokenValidSeconds;
    }

    public void setTokenValidSeconds(Long tokenValidSeconds) {
        TokenManager.tokenValidSeconds = tokenValidSeconds;
    }

    public static String getSignSalt() {
        return signSalt;
    }

    public void setSignSalt(String signSalt) {
        TokenManager.signSalt = signSalt;
    }

    public void setRedis(RedisTemplate redis) {
        this.redis = redis;
    }


}
